package cartagows.wsframework.wscoordination;

import java.util.UUID;

import org.apache.axiom.om.OMElement;

import cartago.ArtifactId;
import cartago.CartagoException;
import cartago.Op;
import cartago.OpFeedbackParam;
import cartago.OpRequestTimeoutException;
import cartago.util.agent.NoPerceptionException;
import cartagows.CartagowsParam;
import cartagows.WSMsgInfo;
import cartagows.util.WSAgent;
import cartagows.util.XMLib;
import cartagows.wsframework.core.FaultBuilder;
import cartagows.wsframework.wsaddressing.WSAddressingMessageElem;
import cartagows.wsframework.wsaddressing.WSAddressingParam;
import cartagows.wsframework.wsatomictransaction.WSAtomicTransactionParam;
import cartagows.wsframework.wsbusinessactivities.WSBusinessActivitiesParam;

public class ActivationService extends WSAgent{

	private String activityIdentifier;
	private ArtifactId wsPanel; 
	private ArtifactId activityRegistry;
	private ArtifactId messagesWarehouse;
	
	public ActivationService(String agentName) throws CartagoException{
		super(agentName);
		wsPanel = makeArtifact(WSCoordinationParam.ACTIVATION_SERVICE_WSPANEL_DEF_NAME,
				CartagowsParam.WSPANEL_CLASS_PATH,
				new Object[]{WSCoordinationParam.WSDL_URI,WSCoordinationParam.ACTIVATION_SERVICE_NAME});
		activityRegistry = lookupArtifact(WSCoordinationParam.ACTIVITIES_REGISTRY_DEF_NAME);
		messagesWarehouse = lookupArtifact(WSCoordinationParam.ACTIVITIES_MSG_WAREHOUSE_DEF_NAME);
	}
	
	public void run() {

		log("[ACTIVATION_SERVICE:]Starting");
		
		while(true){

			try {

				OMElement outputMsg = null;
				OpFeedbackParam<WSMsgInfo> res = new OpFeedbackParam<WSMsgInfo>();
				//Waiting for requests
				log("[ACTIVATION_SERVICE:]Waiting requests");
				
				doAction(wsPanel, new Op("getWSMsg", res));
				
				log("[ACTIVATION_SERVICE:]Request found");
				
				WSMsgInfo inputMsg = res.get();
				String opName = inputMsg.getOperationName();

				//Check if the operation is WSCoordinationWSDLOperation.CREATE_CONTEXT
				if (opName.equals(WSCoordinationWSDLOperation.CREATE_CONTEXT)) {

					log("[ACTIVATION_SERVICE:]CreateCoordinationContextOperation found");

					//Request message check
					OMElement msgBody = XMLib.getInstance().buildElementFromString(inputMsg.getBody());
					String coordType = XMLib.getInstance().getElementValue(WSCoordinationMessageElem.CREATE_CONTEXT,
							WSCoordinationMessageElem.COORDINATION_TYPE, msgBody);

					//Error: Bad message received
					if(coordType==null){
						log("[ACTIVATION_SERVICE:]Error: Bad message");
						outputMsg = FaultBuilder.getInstance().buildSOAPFault(
								WSCoordinationErrorParam.FAULT_INVALID_PARAMETER_CODE,
								WSCoordinationErrorParam.FAULT_INVALID_PARAMETER_SUBCODE,
								WSCoordinationErrorParam.FAULT_INVALID_PARAMETER_REASON, "");
					}
					else{
						//Error: wrong coordination type 
						if((!coordType.equals(WSAtomicTransactionParam.AT)) && !(coordType.equals(WSBusinessActivitiesParam.BA_MIXED_OUTCOME)) 
								&& !(coordType.equals(WSBusinessActivitiesParam.BA_ATOMIC_OUTCOME))){
							
							log("[ACTIVATION_SERVICE:]Wrong coordination protocol provided");						
							outputMsg = FaultBuilder.getInstance().buildSOAPFault(WSCoordinationErrorParam.FAULT_INVALID_PROTOCOL_CODE, WSCoordinationErrorParam.FAULT_INVALID_PROTOCOL_SUBCODE, WSCoordinationErrorParam.FAULT_INVALID_PROTOCOL_REASON, "");
						}
						
						//Valid CoordinationType founded
						else{
							
							//Creation of the activity identifier
							activityIdentifier = UUID.randomUUID().toString();
							
							//Registration of the new activity into the activitiesregistry and into the
							//messagewarehouse
							doAction(activityRegistry, new Op("registerNewActivity", activityIdentifier));
							
							doAction(messagesWarehouse, new Op("addActivity", activityIdentifier));
							
							//Creation of the response message
							outputMsg = createCoordinationContextResponseMsg(coordType, activityIdentifier);
							
							if(outputMsg==null){
								log("[ACTIVATION_SERVICE:]Error in creating the response message");
								outputMsg = FaultBuilder.getInstance().buildSOAPFault(
										WSCoordinationErrorParam.FAULT_CANNOT_CREATE_CODE,
										WSCoordinationErrorParam.FAULT_CANNOT_CREATE_SUBCODE,
										WSCoordinationErrorParam.FAULT_CANNOT_CREATE_REASON, "");
							}
						}
						
						log("[ACTIVATION_SERVICE:]Sending reply");
						
						//Sending the reply to the service requestor
						try {
							OpFeedbackParam<String> replyId = new  OpFeedbackParam<String>();
							doAction(wsPanel, new Op("sendWSReply", inputMsg, outputMsg.toString(), replyId), CartagowsParam.LONG_TIMEOUT);
							log("[ACTIVATION_SERVICE:]Reply sent successfully - id: " + replyId.get());
						} catch (NoPerceptionException ex) {
							log("[ACTIVATION_SERVICE:]Reply failed.");
						}
					}
				}
			}
			catch(OpRequestTimeoutException ex){
				log("[ACTIVATION_SERVICE:]No msg");
			}
			catch (Exception ex) {
				log("[ACTIVATION_SERVICE:]"+ ex.getMessage() +" "+ ex.getCause());
				ex.printStackTrace();
			}
		}
	}
	
	private OMElement createCoordinationContextResponseMsg(String coordType, String actiondIdentifier){

		OMElement msg = XMLib.getInstance().buildElement(WSCoordinationMessageElem.CREATE_CONTEXT_RESPONSE);
		OMElement coordinationContext = XMLib.getInstance().buildElement(WSCoordinationMessageElem.COORDINATION_CONTEXT);
	    OMElement id = XMLib.getInstance().buildElement(WSCoordinationMessageElem.IDENTIFIER, actiondIdentifier);
	    OMElement coordinationType = XMLib.getInstance().buildElement(WSCoordinationMessageElem.COORDINATION_TYPE, coordType);
	    OMElement registrationService = XMLib.getInstance().buildElement(WSCoordinationMessageElem.REGISTRATION_SERVICE);
	    OMElement address = XMLib.getInstance().buildElement(WSAddressingMessageElem.ADDRESS, WSCoordinationParam.REGISTRATION_SERVICE_DEF_EPR, WSAddressingParam.NAMESPACE, WSAddressingParam.NAMESPACE_PREFIX);

	    XMLib.getInstance().addChildNode(registrationService, address);
	    XMLib.getInstance().addChildNode(coordinationContext, id);
	    XMLib.getInstance().addChildNode(coordinationContext, coordinationType);
	    XMLib.getInstance().addChildNode(coordinationContext, registrationService);
	    XMLib.getInstance().addChildNode(msg, coordinationContext);
		return msg;
	}
}